package com.zdyt.opc.config;


import com.zdyt.opc.common.ServerListState;
import org.jinterop.dcom.common.JIException;
import org.openscada.opc.lib.common.ConnectionInformation;
import org.openscada.opc.lib.da.AutoReconnectController;
import org.openscada.opc.lib.da.Server;
import org.openscada.opc.lib.da.ServerConnectionStateListener;
import org.openscada.opc.lib.list.ServerList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.UnknownHostException;
import java.util.concurrent.Executors;


public  class OpcClient {

    private static Logger logger = LoggerFactory.getLogger(OpcClient.class);

    private ServerList serverList;

    private AutoReconnectController mServerController; // OPCServer 有重连功能的包装对象

    private Server mServer; // OPCServer 核心

    private ConnectionInformation ci;  // 连接基本信息对象

    private volatile boolean mstate;

    private volatile ServerListState sstate = ServerListState.NOT_CAN_CONNECTED;

    protected OpcClient(String host,String user,String password,String domain,String progId)  {
//        createBaseConnectInformation(host,user,password,domain);
//        // 若配置了progId，则在初始化时就连接
//        if (progId != null){
//            this.ci.setProgId(progId);
//            init();
//        }
    }

    @Deprecated
    private void init(){

        // 1. 设置 ServerList  其中若连接不上
        setServerList();

        if (sstate == ServerListState.CAN_CONNECTED){
            // 2. 设置Clsid
            setCiClsidWithServerList();
            // 3. 连接
            doConnect(null);
        }
    }


    // 设置基本信息，并尝试是否能连接host
    public synchronized boolean tryConnectAndSetInfo(String host,String user,String password,String domain) {

        // 1. 已经在连接状态 ,需要断开连接
        if (isConnected()){
            disConnectServer(); //断连接，并清除状态数据
        }

        // 2. 设置基本连接信息
        createBaseConnectInformation(host,user,password,domain);

        // 3. ServerList
        setServerList();

        return isServerListConnected();
    }

    public synchronized void connectTargetOpcServer(String progId,ServerConnectionStateListener listener){
        if (isServerListConnected()){
            ci.setProgId(progId);
            setCiClsidWithServerList();
            doConnect(listener);
        }
    }

    // 断连OPCServer  清空Server等状态数据
    public void disConnectServer(){
        this.mServerController.disconnect();
        logger.info("**********断开OPCServer!*********");
        clear();
    }

    private void clear() {
        this.mServerController = null;
        this.mServer = null;
        this.sstate = ServerListState.NOT_CAN_CONNECTED;
    }

    // OPCServer 连接操作， 有自动重连功能
    private void doConnect(ServerConnectionStateListener listener){
        if (sstate == ServerListState.CAN_CONNECTED){
            this.mServer = new Server(ci, Executors.newSingleThreadScheduledExecutor());
            this.mServer.addStateListener(new OPCStateListener());  // 设置状态监听器

            // 添加用户自定义 状态监听器
            if (listener != null){
                this.mServer.addStateListener(listener);
            }

            // 自动重连 OPCServer
            this.mServerController = new AutoReconnectController(mServer);
            this.mServerController.connect();
        }
    }

    // 判断OPCServer是否连接
    public boolean isConnected(){
        return mstate;
    }

    // 判断 ServerList连接host 是否可以连接
    public boolean isServerListConnected(){
        return sstate == ServerListState.CAN_CONNECTED;
    }


    // 获取当前 连接 OPCServer 的 ProgID
    public String getProgId(){
        return ci.getProgId();
    }


    public Server getmServer() {
        return mServer;
    }


    /**
     * 根据ServerList 和 progid 获取Clsid
     */
    private void setCiClsidWithServerList(){
        if (sstate == ServerListState.CAN_CONNECTED){
            if (this.ci.getProgId() != null){
                try {
                    this.ci.setClsid(serverList.getClsIdFromProgId(ci.getProgId()));
                } catch (JIException e) {
                    logger.error(e.getMessage());
                }
            }
        }
    }


    /**
     * 设置ServerList
     */
    private void setServerList(){
        try {
            this.serverList = new ServerList(ci.getHost(), ci.getUser(), ci.getPassword(),ci.getDomain());
            sstate = ServerListState.CAN_CONNECTED;
        } catch (UnknownHostException | JIException e) {
            logger.info(e.getMessage());
            sstate = ServerListState.NOT_CAN_CONNECTED;
        }

    }


    /**
     * 创建连接基本信息
     */
    private void createBaseConnectInformation(String host,String user,String password,String domain){
        // 根据 progId  设置clsid
        this.ci = new ConnectionInformation();
        this.ci.setHost(host);
        this.ci.setUser(user);
        this.ci.setPassword(password);
        this.ci.setDomain(domain);
    }



    public ConnectionInformation getCi() {
        return ci;
    }

    public ServerList getServerList() {
        return serverList;
    }

    // OPCServer状态监听器
    class OPCStateListener implements ServerConnectionStateListener {

        @Override
        public void connectionStateChanged(boolean connected) {
            OpcClient.this.mstate = connected;
            if (connected){
                logger.info("连接OPCServer【{}】成功",OpcClient.this.ci.getProgId());
            }
        }
    }

}
